Shader "NPR/02 SimpleNPR V2"
{
    Properties
    {
        _BaseColor("Color", Color) = (1, 1, 1, 1)
        _BaseMap("Base Map", 2D) = "white" {}

        [Space(20)]
        _ShadowRange("Shadow Range",Range(0,1)) = 0.5
        _ShadowColor("Shadow Color",Color) = (0.5,0.5,0.5,1)
        
        [Space(10)]
        [Toggle(OFF_SHADOW_SMOOTH)] Smooth("Shadow Smooth Enabled",Float) = 0
        _ShadowSmooth("Shadow Smooth",Range(0,1)) = 0.1

        [Space(20)]
        _RimLightColor("Rim Light Color",Color) = (0.5, 0.5, 0.5,1)
        _RimLightWidth("Rim Light Width",Range(0,1)) = 0.5

        [Space(20)]
        _OutLineColor("OutLine Color",Color) =(0,0,0,1)
        _OutlineWidth("Outline Width",Float) =1

        [Space(20)]
        [Toggle(OFF_FACE_SDF)] FaceSDF("Face SDF Enabled",Float) = 0
        [NoScaleOffset] _FaceSDFMap("Face SDF Map",2D)= "white" {}
        _FaceShadowRange ("Face Shadow Range",Range(0,2))= 1

    }
    SubShader
    {
        Tags
        {
            "RenderPipeline" = "UniversalPipeline"
            "LightMode" = "UniversalForward"
            "Queue" = "Geometry"
        }
        Cull Off

        HLSLINCLUDE
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
        #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"

        #pragma shader_feature OFF_SHADOW_SMOOTH
        #pragma shader_feature OFF_FACE_SDF


        TEXTURE2D(_BaseMap);
        SAMPLER(sampler_BaseMap);
        TEXTURE2D(_FaceSDFMap);
        SAMPLER(sampler_FaceSDFMap);

        CBUFFER_START(UnityPerMaterial)
            half4 _BaseMap_ST;
            half4 _BaseColor;

            half4 _ShadowColor;
            half _ShadowRange;
            half _FaceShadowRange;
            half _ShadowSmooth;

            half4 _RimLightColor;
            half _RimLightWidth;

            half4 _OutLineColor;
            half _OutlineWidth;


        CBUFFER_END
        ENDHLSL

        pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            struct a2v
            {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float2 texcoord : TEXCOORD;
            };

            struct v2f
            {
                float4 positionCS : SV_POSITION;
                float3 positionWS : TEXCOORD0;
                float3 normalWS : NORMAL;
                float2 uv : TEXCOORD1;
            };

            v2f vert(a2v input)
            {
                v2f output;
                output.positionCS = TransformObjectToHClip(input.positionOS.xyz);
                output.positionWS = TransformObjectToWorld(input.positionOS.xyz);
                output.normalWS = TransformObjectToWorldNormal(input.normalOS.xyz);
                output.uv = TRANSFORM_TEX(input.texcoord, _BaseMap);

                return output;
            }

            half4 frag(v2f input):SV_Target
            {
                Light light = GetMainLight();
                half3 normalWS = normalize(input.normalWS);
                half3 viewDir = normalize(GetCameraPositionWS() - input.positionWS);

                half3 fianlCol = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).rgb * _BaseColor.rgb;

                #ifndef OFF_FACE_SDF
                    half HNdotL = saturate(dot(normalWS, light.direction) * 0.5h + 0.5h);

                    # ifndef OFF_SHADOW_SMOOTH
                        half cartoon = step(_ShadowRange, HNdotL);
                    #else
                        half cartoon = smoothstep (_ShadowRange * (1 - _ShadowSmooth), _ShadowRange, HNdotL);
                    #endif
                #else
                    half3 leftDir = TransformObjectToWorld(float3(-1, 0, 0));
                    half3 frontDir = TransformObjectToWorld(float3(0, 0, 1));
                    half FdotL = dot(normalize(frontDir.xz), normalize(light.direction.xz));
                    
                    half inverse = normalize(dot(leftDir.xz, light.direction.xz));
                    half2 selectUV = float2(input.uv.x * inverse, input.uv.y);
                    half faseSDFMap = SAMPLE_TEXTURE2D(_FaceSDFMap, sampler_FaceSDFMap, selectUV).a;
                    half threshold = 0.5 - FdotL * 0.5;
                
                    # ifndef OFF_SHADOW_SMOOTH
                        half cartoon = step(threshold, pow(abs(faseSDFMap),_FaceShadowRange));
                    #else
                        half cartoon = smoothstep (threshold * (1 - _ShadowSmooth), threshold, pow(abs(faseSDFMap),_FaceShadowRange));
                    #endif
                #endif

                _ShadowColor += (1 - _ShadowColor.a);
                half3 cartoonCol = _ShadowColor.rgb * (1 - cartoon) + cartoon;
                fianlCol.rgb *= cartoonCol.rgb;

                half3 ddxy = normalize(cross(ddx(input.positionWS), ddy(input.positionWS)));
                half frontMask = dot(ddxy, -normalWS);

                half NdotV = abs(1 - dot(normalWS, viewDir));
                _RimLightColor *= _RimLightColor.a;
                half3 rimCol = _RimLightColor.rgb * saturate(step(1 - _RimLightWidth, NdotV) * frontMask);
                fianlCol.rgb += rimCol;

                return half4(fianlCol.rgb, 1);
            }
            ENDHLSL
        }

        Pass
        {
            Tags
            {
                "LightMode" = "SRPDefaultUnlit"
            }

            Cull Front

            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag


            struct a2v
            {
                float4 positionOS : POSITION;
                float3 normalOS : NORMAL;
                float4 color :COLOR;
            };

            struct v2f
            {
                float4 positionCS : SV_POSITION;
                float4 color : COLOR;
            };


            v2f vert(a2v input)
            {
                v2f output;

                output.positionCS = TransformObjectToHClip(input.positionOS.xyz + input.normalOS * _OutlineWidth * 0.01 * input.color.a);
                output.color = input.color;
                return output;
            }

            half4 frag(v2f input) : SV_TARGET
            {
                return _OutLineColor;
            }
            ENDHLSL
        }
    }
}